package com.eagle.videoboot.config;


import com.eagle.videoboot.constants.RedisConstant;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.Set;

/**
 * @Author：chenaiwei
 * @Description：Redis序列化
 * @CreateDate：2019/8/27 16:42
 */
@Configuration
@Slf4j
public class RedisConfig {

	@Autowired
	RedisPropsConfig redisPropsConfig;

	@Bean(name = "jedisPoolConfig")
	JedisPoolConfig jedisPoolConfig() {
		log.info("JedisPoolConfig init");
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxTotal(5000);
		jedisPoolConfig.setMaxIdle(this.redisPropsConfig.getMaxIdle());
		jedisPoolConfig.setMaxWaitMillis(this.redisPropsConfig.getMaxWait());
		jedisPoolConfig.setTestOnBorrow(true);
		jedisPoolConfig.setTestOnReturn(true);
		jedisPoolConfig.setTestWhileIdle(true);
		return jedisPoolConfig;
	}

	@Bean
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.SENTINEL, matchIfMissing = true)
	public RedisSentinelConfiguration redisSentinelConfiguration(){
		log.info("redis sentinel init");
		Set<String> nodes = new HashSet<>();
		for(String node : this.redisPropsConfig.getSentinelAddresses().split(",")){
			if(node != null && !"".equals(node)){
				nodes.add(node);
			}
		}
		RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(this.redisPropsConfig.getMasterName(),nodes);
		return redisSentinelConfiguration;
	}


	@Bean
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.SENTINEL, matchIfMissing = true)
	public JedisConnectionFactory jedisSentinelConnectionFactory(RedisSentinelConfiguration redisSentinelConfiguration, JedisPoolConfig jedisPoolConfig){
		log.info("JedisConnectionFactory sentinel init");
		JedisConnectionFactory jedisSentinelConnectionFactory  = new JedisConnectionFactory(redisSentinelConfiguration, jedisPoolConfig);
		jedisSentinelConnectionFactory.setPassword(this.redisPropsConfig.getPassword());
		jedisSentinelConnectionFactory.setUsePool(true);
		jedisSentinelConnectionFactory.setTimeout(20000);
		jedisSentinelConnectionFactory.afterPropertiesSet();
		return jedisSentinelConnectionFactory;
	}

	@Bean(value = "redisTemplate")
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.SENTINEL, matchIfMissing = true)
	public RedisTemplate getRedisTemplate(JedisConnectionFactory jedisSentinelConnectionFactory){
		return this.initRedisTemplate(jedisSentinelConnectionFactory);
	}

	//=================================SENTINEL config end=============================================================

	@Bean
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.CLUSTER)
	public RedisClusterConfiguration redisClusterConfiguration(){
		log.info("redis cluster init");
		RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
		String[] serverArray = this.redisPropsConfig.getClusterAddresses().split(",");
		Set<RedisNode> nodes = new HashSet<RedisNode>();
		for(String ipPort:serverArray){
			String[] ipAndPort = ipPort.split(":");
			nodes.add(new RedisNode(ipAndPort[0].trim(),Integer.valueOf(ipAndPort[1])));
		}
		redisClusterConfiguration.setClusterNodes(nodes);
		redisClusterConfiguration.setMaxRedirects(6);
		redisClusterConfiguration.setPassword(RedisPassword.of(this.redisPropsConfig.getPassword()));
		return redisClusterConfiguration;
	}

	/**
	 * Factory配置
	 * @return JedisConnectionFactory
	 */
	@Bean
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.CLUSTER)
	public JedisConnectionFactory jedisClusterConnectionFactory(RedisClusterConfiguration redisClusterConfiguration, JedisPoolConfig jedisPoolConfig){
		log.info("JedisConnectionFactory cluster init");
		JedisConnectionFactory jedisConnectionFactory  = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
		jedisConnectionFactory.setUsePool(true);
		jedisConnectionFactory.setTimeout(20000);
		jedisConnectionFactory.afterPropertiesSet();
		return jedisConnectionFactory;
	}

	/**
	 *
	 * @return RedisTemplate
	 */
	@Bean(value = "redisTemplate")
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.CLUSTER)
	public RedisTemplate getRedisClusterTemplate(JedisConnectionFactory jedisClusterConnectionFactory){
		return this.initRedisTemplate(jedisClusterConnectionFactory);
	}


//=================================CLUSTER config end=============================================================

	@Bean
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.STANDALONE, matchIfMissing = true)
	public RedisStandaloneConfiguration redisStandaloneConfiguration(){
		log.info("redis standalone init");
		RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(this.redisPropsConfig.getHostName(),
				this.redisPropsConfig.getPort());
		return redisStandaloneConfiguration;
	}


	@Bean
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.STANDALONE, matchIfMissing = true)
	public JedisConnectionFactory jedisStandaloneConnectionFactory(JedisPoolConfig jedisPoolConfig){
		log.info("JedisConnectionFactory Standalone init");
		JedisConnectionFactory jedisStandaloneConnectionFactory  = new JedisConnectionFactory(jedisPoolConfig);
		return jedisStandaloneConnectionFactory;
	}

	@Bean(value = "redisTemplate")
	@ConditionalOnProperty(prefix = "redis", name = "mode", havingValue = RedisConstant.STANDALONE, matchIfMissing = true)
	public RedisTemplate getRedisStandaloneTemplate(JedisConnectionFactory jedisStandaloneConnectionFactory){
		return this.initRedisTemplate(jedisStandaloneConnectionFactory);
	}

//=================================STANDALONE config end=============================================================

	public RedisTemplate initRedisTemplate(JedisConnectionFactory jedisConnectionFactory){
		log.info("RedisTemplate init");
		RedisTemplate redisTemplate = new RedisTemplate();
		redisTemplate.setConnectionFactory(jedisConnectionFactory);
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper objectMapper = new ObjectMapper();
//		//这将使所有成员字段都可以序列化，而不需要进一步的注释，
//		//而不仅仅是公共字段（默认设置）
		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
		redisTemplate.setKeySerializer(new StringRedisSerializer());//key属性
		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);//value属性
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}
}
